Attributes of Graphics Primitives (H&B Chapter 4) |
Color Look-up Table
(CLUT)
Gray Scale
Other Parameters (Alpha)
Normally Use GLUT
functions in C/C++ :
glutInitDisplayMode
(GLUT_SINGLE | GLUT_RGB);
BUT!!!
These
functions not implemented in Jogl !
Must
use: gl.glEnable(GL.GL_COLOR_RGB);
Setting Colors:
glColor* (colorComponents);
glColor3f
(0.0, 1.0, 1.0);
glColor3i
(0, 255, 255);
gl.glBegin(GL.GL_TRIANGLES);
gl.glColor3f(1.0f, 0.0f, 0.0f); // red
gl.glVertex3f( 0.0f, 1.0f, 0.0f); // Top
gl.glColor3f(0.0f, 1.0f, 0.0f); // green
gl.glVertex3f(-1.0f,-1.0f, 0.0f); // Bottom Left
gl.glColor3f(0.0f, 0.0f, 1.0f); // blue
gl.glVertex3f( 1.0f,-1.0f, 0.0f); // Bottom Right
gl.glEnd();
Example:
import java.awt.*;
import java.awt.event.*;
import net.java.games.jogl.*;
import net.java.games.jogl.util.*;
public class Color1
{
public static
void main(String[] args)
{
Frame
frame = new Frame("Color1");
GLCanvas
canvas = GLDrawableFactory.getFactory().createGLCanvas(new GLCapabilities());
canvas.addGLEventListener(new Renderer());
frame.add(canvas);
frame.setSize(400, 300);
frame.addWindowListener(new WindowAdapter()
{
public
void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
frame.show();
canvas.requestFocus();
}
static class Renderer implements
GLEventListener, KeyListener
{
public void display(GLDrawable gLDrawable)
{
final GL gl = gLDrawable.getGL();
gl.glClear (GL.GL_COLOR_BUFFER_BIT);//
Set display to color.
gl.glMatrixMode (GL.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glBegin(GL.GL_TRIANGLES); // Drawing Using Triangles
gl.glColor3f(1.0f, 0.0f, 0.0f); // Set color to red
gl.glVertex2i( 100, 140); // Top
gl.glColor3f(0.0f, 1.0f, 0.0f); // Set color to green
gl.glVertex2i(20,20); // Bottom Left
gl.glColor3f(0.0f, 0.0f, 1.0f); // Set color to blue
gl.glVertex2i(180,20); // Bottom Right
gl.glEnd(); // Finished Drawing The Triangle
}
public
void init(GLDrawable gLDrawable)
{
final
GL gl = gLDrawable.getGL();
final
GLU glu = gLDrawable.getGLU();
gl.glMatrixMode (GL.GL_PROJECTION);
gl.glClearColor
(0.0f, 0.0f, 0.0f, 0.0f); //set
background to white
glu.gluOrtho2D (0.0, 200.0, 0.0, 150.0); // define drawing area
gLDrawable.addKeyListener(this);
}
public void displayChanged(GLDrawable
gLDrawable, boolean modeChanged, boolean deviceChanged)
{
}
public void reshape(GLDrawable gLDrawable,
int x, int y, int width, int height)
{
}
public
void keyPressed(KeyEvent e)
{
if
(e.getKeyCode() == KeyEvent.VK_ESCAPE)
System.exit(0);
}
public
void keyReleased(KeyEvent e) {}
public
void keyTyped(KeyEvent e) {}
}
}
Example: Color Look-up
Table
public void
display(GLDrawable gLDrawable)
{
final GL gl = gLDrawable.getGL();
final GLU glu = gLDrawable.getGLU();
float [][] CLUT ={{1.0f,0.0f,0.0f},
{1.0f,0.5f,0.0f},
{1.0f,1.0f,0.0f},{0.0f,1.0f,0.0f},{0.0f,0.0f,1.0f},{1.0f,0.0f,1.0f},
{0.5f,0.0f,0.5f}, {1.0f,0.0f,0.5f}};
int [][] vertex = { {10,130}, {10, 20},{80,
145}, {80, 10}, {130, 120}, {130, 30}, {190, 140}, {190, 10},};
gl.glClear
(GL.GL_COLOR_BUFFER_BIT); // Set
display color.
gl.glMatrixMode (GL.GL_MODELVIEW);
gl.glLoadIdentity();
gl.glBegin(GL.GL_QUAD_STRIP);
gl.glColor3fv(CLUT[0]);
gl.glVertex2iv( vertex[0]);
gl.glColor3fv(CLUT[6]);
gl.glVertex2iv(vertex[1]);
gl.glColor3fv(CLUT[3]);
gl.glVertex2iv( vertex[2]);
gl.glColor3fv(CLUT[1]);
gl.glVertex2iv(vertex[3]);
gl.glColor3fv(CLUT[5]);
gl.glVertex2iv( vertex[4]);
gl.glColor3fv(CLUT[2]);
gl.glVertex2iv(vertex[5]);
gl.glColor3fv(CLUT[4]);
gl.glVertex2iv( vertex[6]);
gl.glColor3fv(CLUT[7]);
gl.glVertex2iv( vertex[7]);
gl.glEnd(); // Finished Drawing
}
Attribute Parameter Any parameter that affects the way a primitive is
displayed.
e.g. color, size = > fundamental properties
visibility => conditional property
Attributes of Basic Display Properties =>
Line Style: [solid | dotted | dashed]
[thick | thin]
Color
Area [one
color | multi-color]
Text [left-to-right
| diagonal | vertical columns]
Line drawing algorithm sets length, spacing, of
segments along path
e.g.
dashed line => inter-dash spacing and length-of-dash are user options
Raster algorithms display line type attributes by
plotting pixel spans
Procedures output sections of contiguous pixels along
path skip over pixels contiguous pixels
Pixel counts for span length and interspan length set
as pixel mask
E.g. 11110000 -> dashed line
Dashes with fixed number of pixels gives unequal
dashes for horizontal vs diagonal lines
Adjust for slope
Each dash is individual line segment
Line Width
Raster algorithm ->
Use standard algorithm for single pixel widths
Other widths plot additional pixels along adjacent
parallel lines
If |m| < 1
plot
vertical span of pixels at each x position along line
If
|m| > 1
Plot
horizontal spans
Problem with spans
Width depends on slope
Produces line ends that are either vertical or
horizontal regardless of slope
Solution Add caps to ends
Butt cap gives square ends perpendicular to path
Round cap filled semicircle
Attributes shape size pattern
Store in pixel mask
e.g.
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
1 |
can change width by changing size of mask at
different positions
Options [solid color | pattern fill]
Fill styles
Hollow with color border
Filled with solid color
Filled with pattern
Also
Edge type
Edge width
color of region
Use an array of colors
e.g.
4 |
0 |
0 |
4 |
2 |
1 |
2 |
1 |
2 |
1 |
2 |
1 |
2 |
Numbers may be colors, intensities, etc.
Patterns are tiled beginning at the reference
position and with extents dx, dy in x and y directions.
Can be applied to scanline fill procedure
Regions displaying sets of parallel lines
Tiled arrays may be used
Issues:
If system sets pattern origin at 0,0 then all
adjacent polygons will have contiguous patterns
A moving polygon with same pattern will appear
transparent
With 1s and 0s => use 0 for transparency
Can use Boolean operations
e.g.
|
|
AND |
|
XOR |
|
||||||||||||||||
Pattern |
Background |
OR |
|
Replace |
|
Boundary or flood fill to combine fill with
background
Where applied => soften fill colors at object
boundaries that are blurred at anti-aliased edges
Allows repaint of area painted with semi-transparency
e.g. linear soft fill -> repaint an area already
painted by merging foreground with background
P =
t F + (1 t) B
Where t = 0 -> 1 for each pixel
P = current pixel RGB
F = foreground color
B = background color
t = (P k B k)/(F k B k) k = R,G,B
glPointSize
(size);
public void display(GLDrawable gLDrawable)
{
final GL
gl = gLDrawable.getGL();
final
GLU glu = gLDrawable.getGLU();
float
[][] CLUT ={{1.0f,0.0f,0.0f},{1.0f,0.5f,0.0f},{1.0f,1.0f,0.0f},
{0.0f,1.0f,0.0f},{0.0f,0.0f,1.0f},{1.0f,0.0f,1.0f},
{0.5f,0.0f,0.5f}, {1.0f,0.0f,0.5f}};
gl.glClear (GL.GL_COLOR_BUFFER_BIT);
// Set display window to color.
gl.glMatrixMode (GL.GL_MODELVIEW);
gl.glLoadIdentity();
double
x = 0.0, y = 0.0, r=0.0, rad,ang=0.0;
float
point = 0.1f;
rad
=(Math.PI/180.0);
for
(int i=0; i<80; i++){
gl.glPointSize(point);
x = r*Math.cos(rad*ang);
y = r*Math.sin(rad*ang);
gl.glBegin(GL.GL_POINTS);
gl.glColor3fv(CLUT[i%8]);
gl.glVertex2f((float)x,(float)y);
gl.glEnd();
r+=3.0;
ang+=10.0;
point += 0.3f;
}
}
public
void init(GLDrawable gLDrawable)
{
final
GL gl = gLDrawable.getGL();
final
GLU glu = gLDrawable.getGLU();
gl.glMatrixMode (GL.GL_PROJECTION);
gl.glClearColor (0.0f, 0.0f, 0.0f, 0.0f); //set background to white
glu.gluOrtho2D (-250.0, 250.0,
-250, 250.0); // define drawing
area
gLDrawable.addKeyListener(this);
}
glLineWidth
(width);
public void display(GLDrawable gLDrawable)
{
final GL
gl = gLDrawable.getGL();
final GLU
glu = gLDrawable.getGLU();
float [][] CLUT ={{1.0f,0.0f,0.0f},{1.0f,0.5f,0.0f},{1.0f,1.0f,0.0f},
{0.0f,1.0f,0.0f},{0.0f,0.0f,1.0f},{1.0f,0.0f,1.0f},
{0.5f,0.0f,0.5f}, {1.0f,0.0f,0.5f}};
gl.glClear (GL.GL_COLOR_BUFFER_BIT);
// Set display window to color.
gl.glMatrixMode (GL.GL_MODELVIEW);
gl.glLoadIdentity();
double
x0 = 0.0, y0 = 0.0, x1,y1, r=200.0, rad,ang=0.0;
float
width = 0.1f;
rad
=(Math.PI/180.0);
for
(int i=0; i<18; i++){
gl.glLineWidth (width);
x1 = r*Math.cos(rad*ang);
y1 = r*Math.sin(rad*ang);
gl.glBegin(GL.GL_LINE_STRIP);
gl.glColor3fv(CLUT[i%8]);
gl.glVertex2f((float)x0,(float)y0);
gl.glVertex2f((float)x1,(float)y1);
gl.glEnd();
ang+=20.0;
width += 1.0f;
}
}
public
void init(GLDrawable gLDrawable)
{
final
GL gl = gLDrawable.getGL();
final
GLU glu = gLDrawable.getGLU();
gl.glMatrixMode (GL.GL_PROJECTION);
gl.glClearColor (0.0f, 0.0f, 0.0f, 0.0f); //set background to white
glu.gluOrtho2D (-250.0, 250.0, -250, 250.0); // define drawing area
gLDrawable.addKeyListener(this);
}
glLineStipple
(repeatFactor, pattern);
glEnable
(GL_LINE_STIPPLE);
glDisable
(GL_LINE_STIPPLE);
public void display(GLDrawable gLDrawable)
{
final GL
gl = gLDrawable.getGL();
final
GLU glu = gLDrawable.getGLU();
float
[][] CLUT ={{1.0f,0.0f,0.0f},{1.0f,0.5f,0.0f},{1.0f,1.0f,0.0f},
{0.0f,1.0f,0.0f},{0.0f,0.0f,1.0f},{1.0f,0.0f,1.0f},
{0.5f,0.0f,0.5f}, {1.0f,0.0f,0.5f}};
short []
dash = {0x1C47,0x00FF,0x0101,0x0B11};
gl.glClear (GL.GL_COLOR_BUFFER_BIT);
// Set display window to color.
gl.glMatrixMode (GL.GL_MODELVIEW);
gl.glLoadIdentity();
double
x0 = -240.0, x1 = 240, y0 = -240.0;
float
width = 3.0f;
gl.glLineWidth (width);
for
(int i=0; i<4; i++){
int pix_length = 1;
for (int j=0; j<5; j++){
gl.glLineStipple
(pix_length, dash[i]);
gl.glBegin(GL.GL_LINES);
gl.glColor3fv(CLUT[(i+j)%8]);
gl.glVertex2f((float)x0,(float)y0);
gl.glVertex2f((float)x1,(float)y0);
gl.glEnd();
pix_length ++;
y0 += 20;
}
y0 += 25;
}
}
public
void init(GLDrawable gLDrawable)
{
final
GL gl = gLDrawable.getGL();
final
GLU glu = gLDrawable.getGLU();
gl.glEnable
(GL.GL_LINE_STIPPLE);
gl.glMatrixMode (GL.GL_PROJECTION);
gl.glClearColor (0.0f, 0.0f, 0.0f, 0.0f); //set background to white
glu.gluOrtho2D (-250.0, 250.0, -250, 250.0); // define drawing area
gLDrawable.addKeyListener(this);
}
·
Standard output
primitives solid anything, pattern
·
Fill primitive solid
circle, rectangle, etc.
·
Two ways of filling;
·
Used in general purpose
packages and paint programs
Scan-line
Polygon Fill
Convex polygons
·
Problem in scan converting a
general n-sided convex polygon: a given scan line will not necessarily cross
all sides of a polygon.
·
Must keep a list of
"active" edges
o i.e., edges that
are crossed by the current scan line.
·
List is kept by having a list
of edges
o sorted by Ytop
value
o using two pointers
§
one to the first active edge
§
second to the last active
edge
·
e.g. changing of active edge
list as a 5-sided polygon is scan converted
o Sorted list of edges (by Ytop)
o List 1
CB is the pointer to top of active edges
CD is the pointer to bottom of active
edges
DE
BA
EA
o List 2
CB
CD
DE is the pointer to top of active edges
BA is the pointer to bottom of active
edges
EA
·
List 3
CB
CD
DE
BA is the pointer to top of active edges
EA is the pointer to bottom of active
edges
Algorithm:
Update active edge pointers (Top Bottom)
Find x-intersections
Draw-lines
1. The scan line may intersect more than twice
o must sort x intersections
2. Vertices: fill from 1 to 2 and from 3 to 4
o need this vertex to count as 2 intersections then each pair
of lines is in polygon interior.
3. An odd number of of intersections and not all pairs are in
interior, e.g., (3 - 4).
o Generate 2 intersections when at a local min or max, else
generate 1 intersection.
o How to generate only 1 intersection at some vertices?
Case 1: Check to see if the y coordinate is monotonically
decreasing, if yes, then increase y by 1.
Case 2: Check to see if the y coordinate is monotonically
increasing, if yes, then decrease y by 1.
In both of the above cases, the vertices will still be
plotted but will only be counted once.
Finds edge intersections with scan-lines
· Slope of edge = m = (yk+1 yk) / (xk+1 xk)
yk+1 yk = 1
· Substitute and rearrange
xk+1 = xk + 1/m
o
where
each successive x intercept is calculated to next integer
· Use integer operations
m = Dy / Dx
o
where
Dx and Dy are differences between
endpoints
xk+1 = xk + Dx / Dy
o
start
with a counter for Dx at 0
o
increment
by Dx
if counter ³ Dy
update x intersection by 1
and decrease counter by Dy
· e.g. m = 7/3
at initial scanline
set counter = 0
set counter increment = 3
move to next 3 scan lines
counter increments to 3, 6, 9
at 3rd scanline 9
> 7
increment x to x+ 1
reset counter to 9-7 = 2
Two major ways to fill a general area:
1. boundary fill
2. flood fill.
o Start at a point inside the figure and paint with a
particular color
o Filling continues until a boundary color is encountered.
Two ways to do this:
1. Four-connected fill: left right up down
Procedure Four_Fill (x, y, fill_col, bound_col:
integer);
var
curr_color: integer;
begin
curr_color := inquire_color(x, y)
if
(curr_color <> bound color) and (curr_color <> fill_col) then
begin
set_pixel(x, y, fill_col)
Four_Fill (x+1, y, fill_col, bound_col);
Four_Fill (x-1, y, fill_col, bound_col);
Four_Fill (x, y+1, fill_col, bound_col);
Four_Fill(
x, y-1, fill_col, bound_col);
end;
1. Problem with four neighbor fill:
2. Eight-connected fill algorithm - test eight adjacent
pixels.
2. add the calls:
eight_fill (x+1, y-1, ...........)
eight_fill (x+1, y+1, ..........)
eight_fill (x-1, y-1, ............)
eight_fill (x-1, y+1, ...........)
o 4-fill and 8-fill algorithms involve recursion which may
consume memory and time.
o Better algorithms are faster, but more complex.
o Make use of pixel runs (horizontal groups of pixels).
1. Fill in row with START pixel
2. Find RIGHTMOST pixel for line above first row - push on
stack
3. Find RIGHTMOST pixel for line below first row - push on
stack
4. Pop stack and goto 1
5. Repeat above until stack empty.
·
General Problem for boundary
fill - requires a unique boundary color
Might do (for 2 overlapping polys)
but should be
Note: if draw front poly 1st will get:
Can use a unique color for boundary, e.g., use -- for
boundary, then
1. draw boundary in
2. fill polygo
3. redraw boundary in final color
(requires extra color for temporary boundary color)
Attributes font, size, color, orientation
Text Attributes
Assorted underlying styles (solid, double,
dotted)
Bold face,
italics, outline, shadow
Scale height and width
Size specified in points
1
pt = .013837 inches or 1/72 inch
Single attribute -> good for single output device but, may not be good
for multi-devices with disparate capabilities
Bundled attributes ->
collection of attributes in a table that are set for different output devices
·
Retrieve current
attributes and parameters
·
Used to check current
state of system
·
Raster algorithms
generate jagged edges
·
Discrete sampling of
continuous function
·
Undersampling (low
frequency sampling) causes aliasing
Nyquest sampling frequency (
fi )
fi = 2 fmax
n = c / l = (nm/sec)/(nm/cycle) = cycles/sec
c =
nm / sec = speed of light
n (wavelength/second)
l = nm / wavelength
cycle
= wavelength
and
Dxsample = Dxcycles / 2
Nyquest
sampling interval for Dxsample interval
where Dxcycles = 1 / fmax or fmax = 1 / Dxcycles
as above n a 1 / l
·
Raster graphics
increases resolution but
·
Frame buffer has limits
·
Require arbitrary
resolution
Super sampling => for
images
·
increase sampling rate
by treating screen as if covered with finer grid
·
use multiple sampling
points across finer grid to determine appropriate intensity level for each
pixel
Lines =>
·
Calculate area of
overlap for each pixel => area sampling
Solutions
1. For greyscale display of
straight line:
·
Divide each pixel into
subpixels
·
Count number of pixels
along line path
·
Set pixel intensity to
subpixel count
o
e.g. divide each pixel in
the 3 x 3 = 9 subpixels
o
use Bresenhams
algorithm to determine coverage
o
Four intensity levels
including black
§
all 3pixels on line
§
2 pixels on line
§
1 pixel on line
§
0 pixel on line
2. Finite size line width
Super sample
·
Set each pixel
intensity proportional to number of pixels inside polygon representing line
area
·
Subpixel in line if LLC
of pixel is inside polygon boundary
o
Adv. => number of
available intensities = total number of pixels in area
o
Adv. => total line
intensity distributed over more pixels
o
Adv.=> can blend
colors
§
e.g. 5 pixels in red, 4
in blue
§
Pixel color = (5 * red
+ 4 * blue)/9
·
Super sampling gives
weight to interior pixels
e.g.
2 |
1 |
2 |
1 |
1 |
2 |
4 |
2 |
0 |
1 |
2 |
1 |
|
0 |
1 |
2 |
Sum of matrix element values
= 16
Weight = value / sum
e.g. at (1,1) weight = 4 / 16/ = Ό
at (0,0) weight = 1 /16
·
Can extend masks over
adjacent pixels
·
Each pixel intensity
proportional to area of overlap of pixel with finite width line
·
Line treated as
rectangle
o
Section between two
vertical/horizontal grid lines => trapezoid
o
Overlap area => how
much trapezoid overlaps pixel
o
Use super sampling
again
·
More accurate
·
Similar to weighted
pixel mask
o
Continuous weighting
surface (filter function)
o
Types of filters: box,
cone, gaussian
o
Integration used
·
Some raster systems can
address subpixel positions
o
Move e-beam closer to
real line
o
Shift pixels b y
fractional amount 1/4., ½, Ύ pixel positions
o
Some systems allow
pixel sizes adjusted
·
Anti-aliasing
compensates for brightness differences
e.g.
horizontal line with number of pixels equal to diagonal is brighter than
diagonal because it is shorter by Φ2
public void display(GLDrawable gLDrawable)
{
final GL
gl = gLDrawable.getGL();
final
GLU glu = gLDrawable.getGLU();
float
[][] CLUT ={{1.0f,0.0f,0.0f,1.0f},{1.0f,0.5f,0.0f,1.0f},{1.0f,1.0f,0.0f,1.0f},
{0.0f,1.0f,0.0f,1.0f},{0.0f,0.0f,1.0f,1.0f},{1.0f,0.0f,1.0f,1.0f},
{0.5f,0.0f,0.5f,1.0f},
{1.0f,0.0f,0.5f,1.0f}};
gl.glClear (GL.GL_COLOR_BUFFER_BIT);
// Set display window to color.
gl.glMatrixMode (GL.GL_MODELVIEW);
gl.glLoadIdentity();
double
x0 = 0.0, y0 = 0.0, x1,y1, r=400.0, rad,ang=0.0;
float
width = 2.0f;
rad
=(Math.PI/180.0);
for
(int i=0; i<18; i++){
gl.glLineWidth (width);
x1 = r*Math.cos(rad*ang);
y1 = r*Math.sin(rad*ang);
gl.glBegin(GL.GL_LINE_STRIP);
gl.glColor4fv(CLUT[i%8]);
gl.glVertex2f((float)x0,(float)y0);
gl.glVertex2f((float)x1,(float)y1);
gl.glEnd();
ang+=20.0;
width += 1.0f;
}
}
public
void init(GLDrawable gLDrawable)
{
final
GL gl = gLDrawable.getGL();
final
GLU glu = gLDrawable.getGLU();
gl.glEnable(GL.GL_RGBA);
gl.glEnable(GL.GL_BLEND);
gl.glBlendFunc(GL.GL_SRC_ALPHA,GL.GL_ONE_MINUS_SRC_ALPHA);
gl.glEnable(GL.GL_LINE_SMOOTH);
gl.glHint(GL.GL_LINE_SMOOTH_HINT,GL.GL_NICEST);
gl.glMatrixMode (GL.GL_PROJECTION);
gl.glClearColor (0.0f, 0.0f, 0.0f, 0.0f); //set background to white
glu.gluOrtho2D (-450.0, 450.0, -450, 450.0); // define drawing area
gLDrawable.addKeyListener(this);
}